{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Sine model Analysis/Synthesis - MusicBricks Tutorial"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Introduction"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This tutorial will guide you through some tools for performing spectral analysis and synthesis using the Essentia library (http://www.essentia.upf.edu). \n",
    "\n",
    "This algorithm shows how to analyze the input signal, and resynthesize it again, allowing to apply new transformations directly on the spectral domain."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You should first install the Essentia library with Python bindings. Installation instructions are detailed here: http://essentia.upf.edu/documentation/installing.html . \n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Processing steps"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# import essentia in streaming mode\n",
    "import essentia\n",
    "import essentia.streaming as es"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "After importing Essentia library, let's import other numerical and plotting tools"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# import matplotlib for plotting\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Define the parameters of the STFT workflow"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# algorithm parameters\n",
    "params = { 'frameSize': 2048, 'hopSize': 512, 'startFromZero': False, 'sampleRate': 44100, \\\n",
    "          'maxnSines': 100,'magnitudeThreshold': -74,'minSineDur': 0.02,'freqDevOffset': 10, \\\n",
    "          'freqDevSlope': 0.001}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Specify input and output audio filenames"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "inputFilename = 'singing-female.wav'\n",
    "outputFilename = 'singing-female-sindemodel.wav'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# create an audio loader and import audio file\n",
    "out = np.array(0)\n",
    "loader = es.MonoLoader(filename = inputFilename, sampleRate = 44100)\n",
    "pool = essentia.Pool()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Define algorithm chain for frame-by-frame process: \n",
    "FrameCutter -> Windowing -> FFT -> IFFT -> OverlapAdd -> AudioWriter"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# algorithm instantation\n",
    "fcut = es.FrameCutter(frameSize = params['frameSize'], hopSize = params['hopSize'], startFromZero =  False);\n",
    "w = es.Windowing(type = \"blackmanharris92\");\n",
    "fft = es.FFT(size = params['frameSize']);\n",
    "smanal = es.SineModelAnal(sampleRate = params['sampleRate'], maxnSines = params['maxnSines'], magnitudeThreshold = params['magnitudeThreshold'], freqDevOffset = params['freqDevOffset'], freqDevSlope = params['freqDevSlope'])\n",
    "smsyn = es.SineModelSynth(sampleRate = params['sampleRate'], fftSize = params['frameSize'], hopSize = params['hopSize'])\n",
    "ifft = es.IFFT(size = params['frameSize']);\n",
    "overl = es.OverlapAdd (frameSize = params['frameSize'], hopSize = params['hopSize'], gain = 1./params['frameSize'] );\n",
    "awrite = es.MonoWriter (filename = outputFilename, sampleRate =  params['sampleRate']);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we set the algorithm network and store the processed audio samples in the output file"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# analysis\n",
    "loader.audio >> fcut.signal\n",
    "fcut.frame >> w.frame\n",
    "w.frame >> fft.frame\n",
    "fft.fft >> smanal.fft\n",
    "# synthesis\n",
    "smanal.magnitudes >> smsyn.magnitudes\n",
    "smanal.frequencies >> smsyn.frequencies\n",
    "smanal.phases >> smsyn.phases\n",
    "smsyn.fft >> ifft.fft\n",
    "ifft.frame >> overl.frame\n",
    "overl.signal >> awrite.audio\n",
    "overl.signal >> (pool, 'audio')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally we run the process that will store an output file in a WAV file"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "essentia.run(loader)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
